using CSharpX;
using System;
using System.Threading.Tasks;
using UnityEngine;

namespace UnityX
{
    public class UIAnimationPage : UIPage
    {
        [Serializable]
        public class AnimationSetting
        {
            public OpenCloseAnimationData open = new OpenCloseAnimationData();
            public OpenCloseAnimationData close = new OpenCloseAnimationData();
        }
        public AnimationSetting m_Animation = new AnimationSetting();

        //内部变量
        private int m_AnimationState = 0;
        private bool m_AnimationUpdateing = false;
        private float m_AnimationBeginTime;
        private RectTransform m_RectTransform;
        private Vector2 m_BeginScaleValue;
        private Vector2 m_EndScaleValue;
        private Vector2 m_BeginMoveValue;
        private Vector2 m_EndMoveValue;
        private float m_BeginTransparentValue;
        private float m_EndTransparentValue;
        private CanvasGroup m_CanvasGroup;

        // 打开页面时调用，可在子类重写此方法以实现自定义功能
        public override void UIOpen()
        {
            if (IsOpen) return;
            IsOpen = true;

            gameObject.SetActive(true);
            if (m_Animation.open.duration > 0.001f)
            {
                StartOpenAnimation();
            }
            else
            {
                OpenEnd();
            }
        }
        // 关闭页面时调用，可在子类重写此方法以实现自定义功能
        public override void UIClose()
        {
            if (!IsOpen) return;
            IsOpen = false;

            if (m_Animation.close.duration > 0.001f)
            {
                StartCloseAnimation();
            }
            else
            {
                CloseEnd();
            }
        }

        // 打开页面时调用，可在子类重写此方法以实现自定义功能
        protected virtual void OpenEnd()
        {
        }
        // 关闭页面时调用，可在子类重写此方法以实现自定义功能
        protected virtual void CloseEnd()
        {
            gameObject.SetActive(false);
        }

        private void StartOpenAnimation()
        {
            if (m_RectTransform == null)
                m_RectTransform = GetComponent<RectTransform>();

            m_AnimationState = 1;
            m_AnimationBeginTime = Time.time;

            if (m_Animation.open.scale.enable)
            {
                m_EndScaleValue = transform.localScale;
                m_BeginScaleValue = m_Animation.open.scale.scaleValue;
                transform.localScale = m_BeginScaleValue;
            }
            if (m_Animation.open.move.enable)
            {
                m_BeginMoveValue = m_Animation.open.move.GetMovePosition(m_RectTransform);
                m_EndMoveValue = m_RectTransform.anchoredPosition;
                m_RectTransform.anchoredPosition = m_BeginMoveValue;
            }
            if (m_Animation.open.transparent.enable)
            {
                CheckCanvasGroup();
                m_BeginTransparentValue = m_Animation.open.transparent.transparentValue;
                m_EndTransparentValue = m_CanvasGroup.alpha;
                m_CanvasGroup.alpha = m_BeginTransparentValue;
            }

            AnimationUpdate();
        }
        private void OpenAnimationEnd()
        {
            if (m_RectTransform == null)
                m_RectTransform = GetComponent<RectTransform>();

            m_AnimationState = 2;
            if (m_Animation.open.scale.enable)
            {
                transform.localScale = m_EndScaleValue;
            }
            if (m_Animation.open.move.enable)
            {
                m_RectTransform.anchoredPosition = m_EndMoveValue;
            }
            if (m_Animation.open.transparent.enable)
            {
                CheckCanvasGroup();
                m_CanvasGroup.alpha = m_EndTransparentValue;
            }
        }

        private void StartCloseAnimation()
        {
            if (m_RectTransform == null)
                m_RectTransform = GetComponent<RectTransform>();

            m_AnimationState = 3;
            m_AnimationBeginTime = Time.time;

            if (m_Animation.close.scale.enable)
            {
                m_BeginScaleValue = transform.localScale;
                m_EndScaleValue = m_Animation.close.scale.scaleValue;
            }
            if (m_Animation.close.move.enable)
            {
                m_BeginMoveValue = m_RectTransform.anchoredPosition;
                m_EndMoveValue = m_Animation.close.move.GetMovePosition(m_RectTransform);
            }
            if (m_Animation.close.transparent.enable)
            {
                CheckCanvasGroup();
                m_BeginTransparentValue = m_CanvasGroup.alpha;
                m_EndTransparentValue = m_Animation.close.transparent.transparentValue;
            }

            AnimationUpdate();
        }
        private void CloseAnimationEnd()
        {
            if (m_RectTransform == null)
                m_RectTransform = GetComponent<RectTransform>();

            m_AnimationState = 0;
            if (m_Animation.close.scale.enable)
            {
                transform.localScale = m_BeginScaleValue;
            }
            if (m_Animation.close.move.enable)
            {
                m_RectTransform.anchoredPosition = m_BeginMoveValue;
            }
            if (m_Animation.close.transparent.enable)
            {
                CheckCanvasGroup();
                m_CanvasGroup.alpha = m_BeginTransparentValue;
            }
        }
        private void CheckCanvasGroup()
        {
            if (m_CanvasGroup == null)
            {
                m_CanvasGroup = GetComponent<CanvasGroup>();
                if (m_CanvasGroup == null)
                {
                    m_CanvasGroup = gameObject.AddComponent<CanvasGroup>();
                }
            }
        }
        private async void AnimationUpdate()
        {
            if (m_AnimationUpdateing)
            {
                return;
            }
            m_AnimationUpdateing = true;
            while (m_AnimationUpdateing)
            {
                await Task.Yield();
#if UNITY_EDITOR
                if (!UnityEditor.EditorApplication.isPlaying)
                {
                    m_AnimationUpdateing = false;
                    return;
                }
#endif
                switch (m_AnimationState)
                {
                    case 0://已经关闭
                        break;
                    case 1://打开中
                        {
                            float elapsedTime = Time.time - m_AnimationBeginTime;
                            if (elapsedTime < m_Animation.open.duration)
                            {
                                if (m_Animation.open.scale.enable)
                                {
                                    float t = Curve.X3(m_Animation.open.scale.curve, elapsedTime / m_Animation.open.duration);
                                    transform.localScale = Vector2.Lerp(m_BeginScaleValue, m_EndScaleValue, t);
                                }
                                if (m_Animation.open.move.enable)
                                {
                                    float t = Curve.X3(m_Animation.open.move.curve, elapsedTime / m_Animation.open.duration);
                                    m_RectTransform.anchoredPosition = Vector2.Lerp(m_BeginMoveValue, m_EndMoveValue, t);
                                }
                                if (m_Animation.open.transparent.enable)
                                {
                                    float t = Curve.X3(m_Animation.open.transparent.curve, elapsedTime / m_Animation.open.duration);
                                    m_CanvasGroup.alpha = Mathf.Lerp(m_BeginTransparentValue, m_EndTransparentValue, t);
                                }
                            }
                            else
                            {
                                m_AnimationUpdateing = false;
                                OpenAnimationEnd();
                                OpenEnd();
                                return;
                            }
                        }
                        break;
                    case 2://已经打开
                        break;
                    case 3://关闭中
                        {
                            float elapsedTime = Time.time - m_AnimationBeginTime;
                            if (elapsedTime < m_Animation.close.duration)
                            {
                                if (m_Animation.close.scale.enable)
                                {
                                    float t = Curve.X3(m_Animation.close.scale.curve, elapsedTime / m_Animation.close.duration);
                                    transform.localScale = Vector2.Lerp(m_BeginScaleValue, m_EndScaleValue, t);
                                }
                                if (m_Animation.close.move.enable)
                                {
                                    float t = Curve.X3(m_Animation.close.move.curve, elapsedTime / m_Animation.close.duration);
                                    m_RectTransform.anchoredPosition = Vector2.Lerp(m_BeginMoveValue, m_EndMoveValue, t);
                                }
                                if (m_Animation.close.transparent.enable)
                                {
                                    float t = Curve.X3(m_Animation.close.transparent.curve, elapsedTime / m_Animation.close.duration);
                                    m_CanvasGroup.alpha = Mathf.Lerp(m_BeginTransparentValue, m_EndTransparentValue, t);
                                }
                            }
                            else
                            {
                                m_AnimationUpdateing = false;
                                CloseAnimationEnd();
                                CloseEnd();
                                return;
                            }
                        }
                        break;
                    default:
                        break;
                }
            }
        }
    }
}
